// FramePacker.js

import { sumMod256 } from './checksum'
import { jspack } from 'jspack'
import { isEqual } from 'lodash'

export default class FramePacker {
  map = {
    GPIO_MESSAGE: {
      sendFormat: '>BBBBBBBBBBBBB',
      sendFields: [
        'cpu',
        'memory',
        'fpga',
        'nvram',
        'sync',
        'cpuNumber',
        'computer',
        'type',
        'param1',
        'param2',
        'cmd',
        'number',
        'state'
      ],
      acceptFormat: '>BBBBBBBBBBBBB',
      acceptFields: [
        'cpu',
        'memory',
        'fpga',
        'nvram',
        'sync',
        'cpuNumber',
        'computer',
        'type',
        'param1',
        'param2',
        'cmd',
        'number',
        'state'
      ],

      acceptChecker(data = {}) {
        return (message) => {
          return message.cmd === 1 && message.computer === data.computerId &&  message.cpuNumber === data.cpuId && message.number === data.number
        }
      }
    },
    RS422_MESSAGE: {
      sendFormat: '>BBB',
      sendFields: ['cmd', 'number', 'state'],
      acceptFormat: '>BBB',
      acceptFields: ['cmd', 'number', 'state'],
      acceptChecker(data = {}) {
        return (message) => {
          return message.cmd === data.cmd && message.number === data.number
        }
      }
    },
    NVRAM_TEST: {
      sendFormat: '>BBB',
      sendFields: ['cmd', 'computerNumber', 'cpuNumber'],
      acceptFormat: '>BBB',
      acceptFields: ['cmd', 'state', 'startArea', 'middleArea', 'endArea', 'size'],
      acceptChecker(data = {}) {
        return (message) => {
          return message.cmd === data.cmd && message.computerNumber === data.computerNumber && message.cpuNumber === data.cpuNumber
        }
      }
    },
    DDR_TEST: {
      sendFormat: '>BBB',
      sendFields: ['cmd', 'computerNumber', 'cpuNumber'],
      acceptFormat: '>BBB',
      acceptFields: ['cmd', 'state', 'area', 'size'],
      acceptChecker(data = {}) {
        return (message) => {
          return message.cmd === data.cmd && message.computerNumber === data.computerNumber && message.cpuNumber === data.cpuNumber
        }
      }
    }
  }
  constructor(frameHeader, frameTrailer) {
    this._frameHeader = frameHeader
    this._frameTrailer = frameTrailer
  }

  pack(payload) {
    const header = this.header(this._frameHeader)
    let msgBuffer = header.concat(payload)
    const footer = this.footer(this._frameTrailer)
    msgBuffer = msgBuffer.concat(footer)
    return Buffer.from(msgBuffer)
  }

  header(frameHeader) {
    const format = '>B'
    return jspack.Pack(format, [frameHeader])
  }

  footer(frameTrailer) {
    const format = '>B'
    return jspack.Pack(format, [frameTrailer])
  }

  messagePacker(format, params) {
    const buffer = this.pack(jspack.Pack(format, params))
    return buffer
  }

  mapMessage(message, { acceptFields }) {
    return Object.fromEntries(acceptFields.map((key, index) => [key, message[index]]))
  }

  unpack(buffer, messageConfig) {
    const header = jspack.Pack('>B', buffer)
    if (!isEqual(header, this.header(this._frameHeader))) {
      return
    }
    const frameTrailer = buffer[buffer.length - 1]
    if (!isEqual(frameTrailer, this._frameTrailer)) {
      return
    }
    const message = buffer.slice(header.length, buffer.length - 1)
    return this.mapMessage(message, messageConfig)
  }
}
